package com.imis.module.system.bus;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imis.base.constant.CommonConstant;
import com.imis.base.constant.enums.ArgumentResponseEnum;
import com.imis.base.globle.response.BaseResponse;
import com.imis.base.globle.response.CommonResponse;
import com.imis.base.util.ConvertUtils;
import com.imis.base.util.PasswordUtil;
import com.imis.module.base.BaseBus;
import com.imis.module.system.model.converter.SysDataSourceConverter;
import com.imis.module.system.model.po.SysDataSource;
import com.imis.module.system.model.ro.PagingQueryDataSourceDTO;
import com.imis.module.system.model.ro.SysDataSourceAddRO;
import com.imis.module.system.model.ro.SysDataSourceUpdateRO;
import com.imis.module.system.model.vo.SysDataSourceVO;
import com.imis.module.system.service.ISysDataSourceService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 系统数据源管理 业务处理类
 * </p>
 *
 * @author XinLau
 * @since 2020-12-30
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysDataSourceBus extends BaseBus {

    /**
     * 数据源
     */
    private final DataSource dataSource;
    /**
     * 数据源创建器
     */
    private final DataSourceCreator dataSourceCreator;

    /**
     * 系统数据源管理 服务类
     */
    private ISysDataSourceService serviceByDataSourceService;

    @Autowired
    public void setDataSourceService(ISysDataSourceService serviceByDataSourceService) {
        this.serviceByDataSourceService = serviceByDataSourceService;
    }

    /**
     * 校验系统数据源重复
     *
     * @param sysDataSourceAdd - DataSource添加对象
     * @return SysDataSource
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/12 15:47
     */
    private SysDataSource dataSourceAddVerification(final SysDataSourceAddRO sysDataSourceAdd) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getOne(Wrappers.<SysDataSource>lambdaQuery().eq(SysDataSource::getPoolName, sysDataSourceAdd.getPoolName()), Boolean.FALSE);
        if (ConvertUtils.isNotEmpty(sysDataSource)) {
            ArgumentResponseEnum.DATASOURCE_ADD_ERR_FREEZE.assertIsTrue(CommonConstant.STATUS_ERR.equals(sysDataSource.getStatus()));
            // 校验系统数据源重复
            ArgumentResponseEnum.CHANGE_USER_PASSWORD_ERR_NON_USER.assertIsNull(sysDataSource, sysDataSourceAdd.getPoolName());
        }
        // 默认数据源状态无效(0无效  1有效)
        sysDataSource = SysDataSourceConverter.INSTANCE.getAddEntity(sysDataSourceAdd);
        return sysDataSource;
    }

    /**
     * 更新系统数据源
     *
     * @param sysDataSourceUpdate - DataSource更新对象
     * @return SysDataSource - 系统数据源
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    private SysDataSource dataSourceUpdateVerification(final SysDataSourceUpdateRO sysDataSourceUpdate) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getById(sysDataSourceUpdate.getId());
        // 校验系统数据源是否存在
        ArgumentResponseEnum.DATASOURCE_UPDATE_ERR_NON.assertNotNull(sysDataSource, sysDataSourceUpdate.getId());
        // 使用中的数据源不允许更新操作
        ArgumentResponseEnum.DATASOURCE_UPDATE_ERR_USING.assertIsTrue(CommonConstant.STATUS_OK.equals(sysDataSource.getStatus()), sysDataSource.getPoolName());
        if (!sysDataSourceUpdate.getPoolName().equalsIgnoreCase(sysDataSource.getPoolName())) {
            sysDataSource = this.serviceByDataSourceService.getOne(Wrappers.<SysDataSource>lambdaQuery().eq(SysDataSource::getPoolName, sysDataSourceUpdate.getPoolName()), Boolean.FALSE);
            // 校验系统数据源名称重复
            ArgumentResponseEnum.DATASOURCE_UPDATE_ERR_NAME_REPEAT.assertIsNull(sysDataSource, sysDataSourceUpdate.getPoolName());
        }
        SysDataSourceConverter.INSTANCE.getUpdateEntity(sysDataSource, sysDataSourceUpdate);
        return sysDataSource;
    }

    /**
     * 分页查询数据源信息
     *
     * @param pagingQueryDataSource - 系统数据源查询对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/12 15:47
     */
    public CommonResponse<Page<SysDataSourceVO>> pagingQueryDataSourceListByParameter(final PagingQueryDataSourceDTO pagingQueryDataSource) {
        // 获取当前所有的数据源
        Map<String, DataSource> dataSourceMap = this.getCurrentDataSourcesPoolName();
        // 查询数据库内的数据源
        Page<SysDataSourceVO> sysDataSourcePage = this.serviceByDataSourceService.pagingQueryDataSourceListByParameter(pagingQueryDataSource);
        List<SysDataSourceVO> sysDataSourceList = sysDataSourcePage.getRecords();
        for (SysDataSourceVO sysDataSource : sysDataSourceList) {
            // 取出数据库内 数据库状态(0无效，1有效) 为 1 的数据进行判断
            if (CommonConstant.STATUS_OK.equals(sysDataSource.getStatus())) {
                // 数据库内 数据库状态(0无效，1有效) 为 1 的，如果不在数据源列表，就给置为无效
                if (!dataSourceMap.containsKey(sysDataSource.getPoolName())) {
                    sysDataSource.setStatus(CommonConstant.STATUS_ERR);
                }
            }
        }
        return new CommonResponse<>(sysDataSourcePage);
    }

    /**
     * 添加系统数据源
     *
     * @param sysDataSourceAdd - DataSource添加对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public BaseResponse addDataSource(final SysDataSourceAddRO sysDataSourceAdd) {
        // 创建新系统数据源 校验系统数据源重复
        SysDataSource sysDataSource = this.dataSourceAddVerification(sysDataSourceAdd);
        boolean save = this.serviceByDataSourceService.save(sysDataSource);
        ArgumentResponseEnum.DATASOURCE_ADD_ERR.assertIsTrue(save, sysDataSourceAdd.getPoolName());
        return new CommonResponse<>();
    }

    /**
     * 冻结系统数据源
     *
     * @param identification - 系统数据源标识
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public BaseResponse freezeDataSourceByIdentification(final Long identification) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getById(identification);
        // 校验系统数据源是否存在
        ArgumentResponseEnum.DATASOURCE_FREEZE_ERR_DATASOURCE_NULL.assertNotNull(sysDataSource, identification);
        // 冻结状态(0无效  1有效)
        sysDataSource.setStatus(CommonConstant.STATUS_ERR);
        boolean update = this.serviceByDataSourceService.updateById(sysDataSource);
        ArgumentResponseEnum.DATASOURCE_FREEZE_ERR.assertIsTrue(update, identification);
        // 核心动态数据源组件
        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) this.dataSource;
        // 删除数据源
        dynamicRoutingDataSource.removeDataSource(sysDataSource.getPoolName());
        return new CommonResponse<>();
    }

    /**
     * 解冻系统数据源
     *
     * @param identification - 系统数据源标识
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public BaseResponse unFreezeDataSourceByIdentification(final Long identification) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getById(identification);
        // 校验系统数据源是否存在
        ArgumentResponseEnum.DATASOURCE_UNFREEZE_ERR_DATASOURCE_NULL.assertNotNull(sysDataSource, identification);
        // 冻结状态(0无效  1有效)
        sysDataSource.setStatus(CommonConstant.STATUS_OK);
        boolean update = this.serviceByDataSourceService.updateById(sysDataSource);
        ArgumentResponseEnum.DATASOURCE_FREEZE_ERR.assertIsTrue(update, identification);
        // 转换数据源
        SysDataSourceVO sysDataSourceVO = SysDataSourceConverter.INSTANCE.getReturnValue(sysDataSource);
        DataSourceProperty dataSourceProperty = SysDataSourceConverter.INSTANCE.getDataSourceProperty(sysDataSourceVO);
        // 防止转换出问题
        ArgumentResponseEnum.DATASOURCE_UNFREEZE_ERR_DATASOURCE_NULL.assertNotNull(dataSourceProperty, identification);
        // 核心动态数据源组件
        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) this.dataSource;
        // 数据源创建
        DataSource dataSource = this.dataSourceCreator.createDataSource(dataSourceProperty);
        // 添加数据源
        dynamicRoutingDataSource.addDataSource(sysDataSource.getPoolName(), dataSource);
        return new CommonResponse<>();
    }

    /**
     * 查看系统数据源
     *
     * @param identification - 系统数据源标识
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public CommonResponse<SysDataSourceVO> queryDataSourceById(final Long identification) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getById(identification);
        // 获取当前所有的数据源
        Map<String, DataSource> dataSourceMap = this.getCurrentDataSourcesPoolName();
        // 取出数据库内 数据库状态(0无效，1有效) 为 1 的数据进行判断
        if (CommonConstant.STATUS_OK.equals(sysDataSource.getStatus())) {
            // 数据库内 数据库状态(0无效，1有效) 为 1 的，如果不在数据源列表，就给置为无效
            if (!dataSourceMap.containsKey(sysDataSource.getPoolName())) {
                sysDataSource.setStatus(CommonConstant.STATUS_ERR);
            }
        }
        return new CommonResponse(SysDataSourceConverter.INSTANCE.getReturnValue(sysDataSource));
    }

    /**
     * 更新系统数据源
     *
     * @param sysDataSourceUpdate - DataSource更新对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public BaseResponse updateById(final SysDataSourceUpdateRO sysDataSourceUpdate) {
        // 更新系统数据源 校验系统数据源更新对象
        SysDataSource sysDataSource = this.dataSourceUpdateVerification(sysDataSourceUpdate);
        boolean update = this.serviceByDataSourceService.updateById(sysDataSource);
        ArgumentResponseEnum.DATASOURCE_FREEZE_ERR.assertIsTrue(update, sysDataSourceUpdate.getId());
        return new CommonResponse<>();
    }

    /**
     * 删除系统数据源
     *
     * @param identification - 系统数据源标识
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public BaseResponse deleteDataSource(final Long identification) {
        SysDataSource sysDataSource = this.serviceByDataSourceService.getById(identification);
        // 校验系统数据源是否存在
        ArgumentResponseEnum.DATASOURCE_DELETE_ERR_DATASOURCE_NULL.assertNotNull(sysDataSource, identification);
        ArgumentResponseEnum.DATASOURCE_FREEZE_ERR.assertIsTrue(CommonConstant.STATUS_OK.equals(sysDataSource.getStatus()), identification);
        boolean remove = this.serviceByDataSourceService.removeById(identification);
        ArgumentResponseEnum.DATASOURCE_DELETE_ERR.assertIsTrue(remove, identification);
        return new CommonResponse<>();
    }

    /**
     * 获取当前所有的数据源
     *
     * @return Map<String, DataSource>  - 当前所有的数据源
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public Map<String, DataSource> getCurrentDataSourcesPoolName() {
        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) this.dataSource;
        // 获取当前所有的数据源
        return dynamicRoutingDataSource.getCurrentDataSources();
    }

    /**
     * 初始化数据源
     *
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public void initializeTheDataSource() {
        // 正常使用的数据源
        List<SysDataSource> dataSourceList = this.serviceByDataSourceService.list(Wrappers.<SysDataSource>lambdaQuery().eq(SysDataSource::getStatus, CommonConstant.STATUS_OK));
        for (SysDataSource sysDataSource : dataSourceList) {
            // 转换数据源
            SysDataSourceVO sysDataSourceVO = SysDataSourceConverter.INSTANCE.getReturnValue(sysDataSource);
            DataSourceProperty dataSourceProperty = SysDataSourceConverter.INSTANCE.getDataSourceProperty(sysDataSourceVO);
            // 核心动态数据源组件
            DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) this.dataSource;
            // 数据源创建
            DataSource dataSource = this.dataSourceCreator.createDataSource(dataSourceProperty);
            // 添加数据源
            dynamicRoutingDataSource.addDataSource(sysDataSource.getPoolName(), dataSource);
        }
    }

    /**
     * 数据源加密串解密
     *
     * @param encryptionString - 加密串
     * @return Result - 返回
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/12/31 15:47
     */
    public CommonResponse<String> decryptionDataSourceEncryptionString(final String encryptionString) {
        String afterDecryption = PasswordUtil.decrypt(encryptionString);
        return new CommonResponse(afterDecryption);
    }

}